package tool

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"

	gpb "gitee.com/cloudapex/protos/crm_order/pb"

	"math/rand"
	"net/url"
	model "service/model/crm_order"
	"sort"
	"strings"
	"time"

	"gitee.com/cloudapex/ulern/util"

	"github.com/iGoogle-ink/gopay"
	//"github.com/iGoogle-ink/gopay/alipay"
	"service/model/alipay"

	"github.com/iGoogle-ink/gopay/wechat"
)

const (
	TRADE_FUNCODE        = "WP001"
	QUERY_FUNCODE        = "MQ002"
	NOTIFY_FUNCODE       = "N001"
	FRONT_NOTIFY_FUNCODE = "N002"
	TRADE_TYPE           = "05"
	TRADE_CURRENCYTYPE   = "156"
	TRADE_CHARSET        = "UTF-8"
	TRADE_DEVICE_TYPE    = "20"
	TRADE_SIGN_TYPE      = "MD5"
	TRADE_QSTRING_EQUAL  = "="
	TRADE_QSTRING_SPLIT  = "&"
	TRADE_FUNCODE_KEY    = "funcode"
	TRADE_DEVICETYPE_KEY = "deviceType"
	TRADE_SIGNTYPE_KEY   = "mhtSignType"
	TRADE_SIGNATURE_KEY  = "mhtSignature"
	SIGNATURE_KEY        = "signature"
	SIGNTYPE_KEY         = "signType"
	VERIFY_HTTPS_CERT    = false
)

//发起微信支付参数
type WxPayServer struct {
	AppId     string `json:"appId"`
	MchId     string `json:"mchId"`
	ApiKey    string `json:"apiKey"`
	NotifyUrl string `json:"notifyUrl"`
	Subject   string `json:"subject"`
	OrderNum  string `json:"ordernum"`
	Total     int64  `json:"total"`
	OpenId    string `json:"openid"`
}

var WxPay WxPayServer

/*
 * 描述: 获取微信接口
 *
 *********************************************************************************/
func (this *WxPayServer) WxPayOrder(ctx context.Context) (string, error) {
	// 初始化微信客户端
	//    appId：应用ID
	//    mchId：商户ID
	//    apiKey：API秘钥值

	initializeWx(ctx)

	client := wechat.NewClient(WxPay.AppId, WxPay.MchId, WxPay.ApiKey, true)
	// 初始化 BodyMap
	bm := make(gopay.BodyMap)
	bm.Set("nonce_str", GetRandomString(32))
	bm.Set("body", "中宇博学教育")
	bm.Set("out_trade_no", this.OrderNum)
	bm.Set("total_fee", this.Total)
	bm.Set("spbill_create_ip", "127.0.0.1")
	bm.Set("notify_url", WxPay.NotifyUrl)
	bm.Set("trade_type", wechat.TradeType_Native)
	bm.Set("sign_type", wechat.SignType_MD5)
	sign := wechat.GetParamSign(WxPay.AppId, WxPay.MchId, WxPay.ApiKey, bm)
	bm.Set("sign", sign)
	// ====同步返回参数验签Sign====
	wxRsp, err := client.UnifiedOrder(bm)
	//fmt.Println(wxRsp)
	ok, err := wechat.VerifySign(WxPay.ApiKey, wechat.SignType_MD5, wxRsp)
	if ok == true {
		return wxRsp.CodeUrl, err
	}
	return "", err
}

func initializeWx(ctx context.Context) {

	if LcPay.ApiUrl != "" {
		return
	}
	in := &gpb.PayParaReq{
		CId:  1,
		Type: 2,
	}
	res, err := model.Order.GetPayParam(ctx, in)
	if err != nil {
		util.Debug("%s", err)
	}
	fmt.Println(err)
	WxPay.NotifyUrl = res.PayParam.NotifyUrl
	WxPay.AppId = res.PayParam.AppId
	WxPay.MchId = res.PayParam.PubKey
	WxPay.ApiKey = res.PayParam.PriKey
}

// 获取随机字符串
//    length：字符串长度
func GetRandomString(length int) string {
	str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
	var (
		result []byte
		b      []byte
		r      *rand.Rand
	)
	b = []byte(str)
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, b[r.Intn(len(b))])
	}
	return string(result)
}

type AliPayServer struct {
	AppId           string  `json:"appId"`
	PrivateKey      string  `json:"privateKey"`
	AliPayPublicKey string  `json:"aliPayPublicKey"`
	NotifyUrl       string  `json:"notifyUrl"`
	Subject         string  `json:"subject"`
	OrderNum        string  `json:"ordernum"`
	Total           float64 `json:"total"`
}

type AutoGenerated struct {
	Code       string `json:"code"`
	Msg        string `json:"msg"`
	OutTradeNo string `json:"out_trade_no"`
	QrCode     string `json:"qr_code"`
}

var AilPay AliPayServer

/*
 * 描述: 获取支付宝接口
 *
 *********************************************************************************/
func (this *AliPayServer) GoPay(ctx context.Context) (string, error) {

	initializeAlipay(ctx)

	util.Debug("%s", AilPay)
	// 初始化支付宝客户端
	client := alipay.NewClient(AilPay.AppId, AilPay.PrivateKey, true)

	client.SetCharset("utf-8"). // 设置字符编码，不设置默认 utf-8
		//SetSignType("RSA2").                    			// 设置签名类型，不设置默认 RSA2
		SetReturnUrl(AilPay.NotifyUrl). // 设置返回URL
		SetNotifyUrl(AilPay.NotifyUrl)  // 设置异步通知URL
	// 初始化 BodyMap
	bm := make(gopay.BodyMap)
	bm.Set("subject", this.Subject)
	bm.Set("out_trade_no", this.OrderNum)
	bm.Set("total_amount", this.Total)
	//请求二维码
	aliRsp, err := client.TradePay(bm)
	fmt.Println(aliRsp)

	if err != nil {
		return "", err
	}
	//fmt.Println(aliRsp.SignData, aliRsp.Sign)
	//支付宝同步返回验签
	ok, err := alipay.VerifySyncSign(AilPay.AliPayPublicKey, aliRsp.SignData, aliRsp.Sign)
	fmt.Println(ok)
	fmt.Println(err)
	fmt.Println(aliRsp.SignData)
	fmt.Println(aliRsp.Sign)
	fmt.Println("90000000000000")

	if true == ok {
		var val AutoGenerated
		json.Unmarshal([]byte(aliRsp.SignData), &val)
		return val.QrCode, nil
	}
	return "", nil
}

func initializeAlipay(ctx context.Context) {

	if AilPay.NotifyUrl != "" {
		return
	}
	in := &gpb.PayParaReq{
		CId:  1,
		Type: 1,
	}
	res, err := model.Order.GetPayParam(ctx, in)
	if err != nil {
		util.Debug("%s", err)
	}
	fmt.Println(err)
	AilPay.NotifyUrl = res.PayParam.NotifyUrl
	AilPay.AppId = res.PayParam.AppId
	AilPay.PrivateKey = res.PayParam.PriKey
	AilPay.AliPayPublicKey = res.PayParam.PubKey
}

type NowPayServer struct {
	AppId        string `json:"appId"`
	Key          string `json:"key"`
	TradeTimeOut string `json:"tradeTimeOut"`
	ApiUrl       string `json:"apiUrl"`
	NotifyUrl    string `json:"notifyUrl"`
	TimeZone     string `json:"timeZone"`
	MhtOrderNo   string `json:"mhtOrderNo"`
	MhtOrderAmt  int64  `json:"mhtOrderAmt"`
	OutPutType   int    `json:"outputType"`
}

var NowPay NowPayServer

/*
 * 描述: 获取聚合扫码接口
 *
 *********************************************************************************/
func (this *NowPayServer) NowPay(ctx context.Context) (string, error) {

	initializeNowPay(ctx)

	var m map[string]interface{}
	m = make(map[string]interface{}, 0)
	m["funcode"] = TRADE_FUNCODE
	m["version"] = "1.0.0"
	m["appId"] = NowPay.AppId
	m["mhtOrderNo"] = this.MhtOrderNo
	m["mhtOrderName"] = "北京中宇博学教育"
	m["mhtCurrencyType"] = TRADE_CURRENCYTYPE
	m["mhtOrderAmt"] = this.MhtOrderAmt
	m["mhtOrderDetail"] = "北京中宇博学教育"
	m["mhtOrderTimeOut"] = 86400
	m["mhtOrderStartTime"] = TimeToStringMiao(time.Now().Unix())
	m["notifyUrl"] = NowPay.NotifyUrl
	m["mhtCharset"] = TRADE_CHARSET
	m["outputType"] = 0
	m["deviceType"] = TRADE_DEVICE_TYPE
	m["mhtLimitPay"] = 0
	m["mhtOrderType"] = TRADE_TYPE
	m["mhtSignType"] = TRADE_SIGN_TYPE
	//算出签名

	Sign := PayCalcSign(m, NowPay.Key)
	m["mhtSignature"] = Sign
	signStrings := "funcode" + "=" + TRADE_FUNCODE + "&" +
		"version" + "=" + "1.0.0" + "&" +
		"appId" + "=" + NowPay.AppId + "&" +
		"mhtOrderNo" + "=" + this.MhtOrderNo + "&" +
		"mhtOrderName" + "=" + url.QueryEscape("北京中宇博学教育") + "&" +
		"mhtCurrencyType" + "=" + TRADE_CURRENCYTYPE + "&" +
		"mhtOrderAmt" + "=" + fmt.Sprintf("%d", this.MhtOrderAmt) + "&" +
		"mhtOrderDetail" + "=" + url.QueryEscape("北京中宇博学教育") + "&" +
		"mhtOrderTimeOut" + "=" + "86400" + "&" +
		"mhtOrderStartTime" + "=" + TimeToStringMiao(time.Now().Unix()) + "&" +
		"notifyUrl" + "=" + url.QueryEscape(NowPay.NotifyUrl) + "&" +
		"mhtCharset" + "=" + TRADE_CHARSET + "&" +
		"outputType" + "=" + "0" + "&" +
		"deviceType" + "=" + TRADE_DEVICE_TYPE + "&" +
		"mhtLimitPay" + "=" + "0" + "&" +
		"mhtOrderType" + "=" + TRADE_TYPE + "&" +
		"mhtSignType" + "=" + TRADE_SIGN_TYPE + "&" +
		"mhtSignature" + "=" + Sign
	fmt.Println(signStrings)

	data, err := util.PayFormPost(NowPay.ApiUrl, signStrings)
	fmt.Println(string(data), err)
	var gettn string
	str := strings.Split(strings.Trim(string(data), "&"), "&")
	for _, row := range str {
		tn := strings.Split(strings.Trim(string(row), "="), "=")
		if tn[0] == "tn" {
			gettn, _ = url.QueryUnescape(tn[1])
		}
	}
	return gettn, nil
}

func initializeNowPay(ctx context.Context) {

	if NowPay.ApiUrl != "" {
		return
	}
	in := &gpb.PayParaReq{
		CId:  1,
		Type: 3,
	}
	res, err := model.Order.GetPayParam(ctx, in)
	if err != nil {
		util.Debug("%s", err)
	}
	fmt.Println(err)
	NowPay.AppId = res.PayParam.AppId
	NowPay.NotifyUrl = res.PayParam.NotifyUrl
	NowPay.Key = res.PayParam.PriKey
	NowPay.TimeZone = "Asia/Shanghai"
	NowPay.ApiUrl = res.PayParam.ApiUrl
	NowPay.TradeTimeOut = "3600"

}

/*
 * 描述: 时间戳转格式化为字符串
 *
 ***************************************************************************/
func TimeToStringMiao(nTimer int64) string {
	tm := time.Unix(nTimer, 0)
	//strTime := tm.Format("2006-01-02 03:04:05 PM")
	return tm.Format("20060102150405")
}

//下单签名
func PayCalcSign(mReq map[string]interface{}, key string) string {

	//fmt.Println("========STEP 1, 对key进行升序排序.========")
	//fmt.Println("微信支付签名计算, API KEY:", key)
	//STEP 1, 对key进行升序排序.
	sorted_keys := make([]string, 0)
	for k, _ := range mReq {
		sorted_keys = append(sorted_keys, k)
	}

	sort.Strings(sorted_keys)

	//fmt.Println("========STEP2, 对key=value的键值对用&连接起来，略过空值========")
	//STEP2, 对key=value的键值对用&连接起来，略过空值
	var signStrings string
	for _, k := range sorted_keys {
		value := fmt.Sprintf("%v", mReq[k])
		if value != "" {
			signStrings = signStrings + k + "=" + value + "&"
		}
	}
	md5Ctx := md5.New()
	//fmt.Println("========STEP3, 在键值对的最后加上key=API_KEY========")
	//STEP3, 在键值对的最后加上key=API_KEY

	if key != "" {
		fmt.Println(key)
		md5Ctx.Write([]byte(key))
		cipherStr := md5Ctx.Sum(nil)
		upperSign := strings.ToLower(hex.EncodeToString(cipherStr))
		signStrings = signStrings + upperSign
	}
	fmt.Println("sing", util.MD5s(signStrings))
	return util.MD5s(signStrings)
}

//func StrMd5Str(strPass string) string {
//	w := md5.New()
//	io.WriteString(w, strPass)
//	return fmt.Sprintf("%x", w.Sum(nil))
//}

//公共参数
type LcPayServer struct {
	MerchantNo    string `json:"merchantNo"`    //商户号
	AccessToken   string `json:"accessToken"`   //令牌
	ApiUrl        string `json:"apiUrl"`        //接口地址
	NotifyUrl     string `json:"notifyUrl"`     //回调地址
	ServiceId     string `json:"serviceId"`     //接口类型
	PayVer        string `json:"payVer"`        //版本号
	TerminalId    string `json:"terminalId"`    //设备号
	PayType       string `json:"payType"`       //支付类型 支付方式，010微信，020 支付宝，060qq钱包，080京东钱包，090口碑，100翼支付
	TerminalTrace string `json:"terminalTrace"` //订单号
	TotalFee      int64  `json:"totalFee"`
	OutPutType    string `json:"outputType"`
}

//处理返回参数
type ResponseJson struct {
	ReturnCode    string      `json:"return_code"`
	ReturnMsg     string      `json:"return_msg"`
	ResultCode    string      `json:"result_code"`
	MerchantName  string      `json:"merchant_name"`
	MerchantNo    string      `json:"merchant_no"`
	TerminalID    string      `json:"terminal_id"`
	TerminalTrace string      `json:"terminal_trace"`
	TerminalTime  string      `json:"terminal_time"`
	TotalFee      string      `json:"total_fee"`
	QrURL         string      `json:"qr_url"`
	Attach        interface{} `json:"attach"`
	KeySiGn       string      `json:"key_si gn"`
}

/*
 * 描述: 聚合扫呗支付回调信息
 ***********************************************************************/
type LcnotifyReq struct {
	Attach         string `json:"attach"`
	ChannelTradeNo string `json:"channel_trade_no"`
	EndTime        string `json:"end_time"`
	KeySign        string `json:"key_sign"`
	MerchantName   string `json:"merchant_name"`
	MerchantNo     string `json:"merchant_no"`
	OutTradeNo     string `json:"out_trade_no"`
	PayType        string `json:"pay_type"`
	ReceiptFee     string `json:"receipt_fee"`
	ResultCode     string `json:"result_code"`
	ReturnCode     string `json:"return_code"`
	ReturnMsg      string `json:"return_msg"`
	TerminalID     string `json:"terminal_id"`
	TerminalTime   string `json:"terminal_time"`
	TerminalTrace  string `json:"terminal_trace"`
	TotalFee       string `json:"total_fee"`
	UserID         string `json:"user_id"`
}

var LcPay LcPayServer

/*
 * 描述: 获取聚合扫码接口
 *
 *********************************************************************************/
func (this *LcPayServer) LcPay(ctx context.Context) (string, error) {

	initialize(ctx)

	//拼接请求参数
	var m map[string]interface{}
	m = make(map[string]interface{}, 0)
	m["pay_ver"] = LcPay.PayVer
	m["pay_type"] = LcPay.PayType
	m["service_id"] = LcPay.ServiceId
	m["merchant_no"] = LcPay.MerchantNo
	m["terminal_id"] = LcPay.TerminalId
	m["terminal_trace"] = this.TerminalTrace
	m["terminal_time"] = TimeToStringMiao(time.Now().Unix())
	m["notify_url"] = LcPay.NotifyUrl
	m["total_fee"] = this.TotalFee
	m["order_body"] = "北京中宇博学教育"
	//算出md5加密签名
	sign := PayLassSign(m, LcPay.AccessToken)
	m["key_sign"] = sign
	mjSon, _ := json.Marshal(m)
	mString := string(mjSon)

	data, err := util.PayJsonPost(LcPay.ApiUrl, mString)
	fmt.Println(string(data))
	var val ResponseJson
	json.Unmarshal(data, &val)

	util.Debug("%s", err)

	if val.ReturnCode != "01" && val.ResultCode != "01" {
		return "", err
	}
	return val.QrURL, nil
}

//下单签名
func PayLassSign(mReq map[string]interface{}, key string) string {

	//fmt.Println("========STEP 1, 对key进行升序排序.========")
	//fmt.Println("微信支付签名计算, API KEY:", key)
	//STEP 1, 对key进行升序排序.
	sorted_keys := make([]string, 0)
	for k, _ := range mReq {
		sorted_keys = append(sorted_keys, k)
	}

	sort.Strings(sorted_keys)

	//fmt.Println("========STEP2, 对key=value的键值对用&连接起来，略过空值========")
	//STEP2, 对key=value的键值对用&连接起来，略过空值
	var signStrings string
	for _, k := range sorted_keys {
		value := fmt.Sprintf("%v", mReq[k])
		if value != "" {
			signStrings = signStrings + k + "=" + value + "&"
		}
	}
	//fmt.Println("========STEP3, 在键值对的最后加上key=API_KEY========")
	//STEP3, 在键值对的最后加上key=API_KEY

	if key != "" {
		signStrings = signStrings + "access_token=" + key
	}
	fmt.Println(signStrings)
	fmt.Println("sing", util.MD5s(signStrings))
	return util.MD5s(signStrings)
}

func initialize(ctx context.Context) {

	if LcPay.ApiUrl != "" {
		return
	}
	in := &gpb.PayParaReq{
		CId:  1,
		Type: 4,
	}
	res, err := model.Order.GetPayParam(ctx, in)
	if err != nil {
		util.Debug("%s", err)
	}

	fmt.Println(err)
	LcPay.PayType = "000"
	LcPay.TerminalId = "11822055"
	LcPay.PayVer = "110"
	LcPay.ServiceId = "016"
	LcPay.AccessToken = res.PayParam.PriKey
	LcPay.MerchantNo = res.PayParam.AppId
	LcPay.NotifyUrl = res.PayParam.NotifyUrl
	LcPay.ApiUrl = res.PayParam.ApiUrl

}
